#include "stdafx.h"
#include "GameAppListener.h"

GameAppListener::GameAppListener( RenderWindow* window )
{	
	m_Window = window;
	WindowEventUtilities::addWindowEventListener(m_Window, this);

	m_DebugOverlay = OverlayManager::getSingleton().getByName("Core/DebugOverlay");

	m_beforeTime = g_Clock->getMillisecondsCPU() / 1000.0f;

	OIS::ParamList pl;
	size_t windowHnd;
	std::ostringstream windowHndStr;

	window->getCustomAttribute("WINDOW", &windowHnd);
	windowHndStr << windowHnd;
	pl.insert(make_pair(std::string("WINDOW"), windowHndStr.str()));
	pl.insert(std::make_pair(std::string("w32_mouse"), std::string("DISCL_FOREGROUND" )));
	pl.insert(std::make_pair(std::string("w32_mouse"), std::string("DISCL_NONEXCLUSIVE")));
	pl.insert(std::make_pair(std::string("w32_keyboard"), std::string("DISCL_FOREGROUND")));
	pl.insert(std::make_pair(std::string("w32_keyboard"), std::string("DISCL_NONEXCLUSIVE")));

	m_InputManager = OIS::InputManager::createInputSystem(pl);

	m_Keyboard = static_cast<OIS::Keyboard*>(
		m_InputManager->createInputObject(OIS::OISKeyboard, true));

	m_Mouse = static_cast<OIS::Mouse*>(
		m_InputManager->createInputObject(OIS::OISMouse, true));
	
	uint w, h, d;
	int l, t;

	window->getMetrics(w, h, d, l, t);

	const OIS::MouseState &mouseState = m_Mouse->getMouseState();
	mouseState.width  = w;
	mouseState.height = h;

	m_EnabledDebugState = false;
	m_IsExitApp = false;

	m_InputHandler = new GameAppInputHandler(this);
	
	m_TranslateVector = Vector3::ZERO;
	m_camMoved = Vector3::ZERO;
	m_MoveScale = 0.0f;
	m_SpeedLimit = 0.0f;
	m_MoveSpeed = 100.0f;
	
	m_UpdateMovement = false;
	m_IsKeyboardInput = false;
	m_IsMouseInput = false;

	m_MoveLeft = false;
	m_MoveRight = false;
	m_MoveFwd = false;
	m_MoveBck = false;

	m_RotateCam = false;
	m_RotateAxisX = 0.0f;
	m_RotateAxisY = 0.0f;

	m_Keyboard->setEventCallback(this);
}

GameAppListener::~GameAppListener()
{
	SAFE_DELETE(m_InputHandler);

	WindowEventUtilities::removeWindowEventListener(m_Window, this);
	windowClosed(m_Window);
}

void GameAppListener::windowResize(RenderWindow* window)
{
	if (!m_Mouse)
		return;

	uint width, height, depth;
	int left, top;
	window->getMetrics(width, height, depth, left, top);

	const OIS::MouseState &ms = m_Mouse->getMouseState();
	ms.width = width;
	ms.height = height;
}

void GameAppListener::windowClosed(RenderWindow* window)
{
	if (m_Window != window)
		return;

	if (!m_InputManager)
		return;

	m_InputManager->destroyInputObject(m_Mouse);
	m_InputManager->destroyInputObject(m_Keyboard);
	m_Mouse = NULL;
	m_Keyboard = NULL;

	OIS::InputManager::destroyInputSystem(m_InputManager);
	m_InputManager = NULL;
}

bool GameAppListener::frameRenderingQueued(const FrameEvent& evt)
{
	if(m_Window->isClosed())	return false;
	
	m_SpeedLimit = m_MoveScale * evt.timeSinceLastFrame;

	m_Keyboard->capture();
	m_Mouse->capture();

	Vector3 lastMotion = m_TranslateVector;

	if (!m_IsKeyboardInput || !m_IsMouseInput)
	{
		m_MoveScale = m_MoveSpeed * evt.timeSinceLastFrame;
		m_TranslateVector = Vector3::ZERO;

		m_camRotX = 0;
		m_camRotY = 0;
	}

	UpdateInputVariable();

	if (m_TranslateVector == Vector3::ZERO)
	{
		m_CurrentSpeed -= evt.timeSinceLastFrame * 0.3f;
		m_TranslateVector = lastMotion;
	}
	else
	{
		m_CurrentSpeed += evt.timeSinceLastFrame;
	}
	
	if (m_CurrentSpeed > 1.0)
		m_CurrentSpeed = 1.0;
	else if(m_CurrentSpeed < 0.0)
		m_CurrentSpeed = 0.0;

	m_TranslateVector *= m_CurrentSpeed;
	
	if (m_UpdateMovement)
	{
		MoveCamera();
		m_UpdateMovement = false;
	}

	m_IsKeyboardInput = false;
	m_IsMouseInput = false;	

	return true;
}

bool GameAppListener::frameEnded(const FrameEvent& evt)
{
	if (m_IsExitApp)
		return false;

	debugState();

	g_App->ChangeActiveSession();

	float t		= g_Clock->getMillisecondsCPU() / 1000.0f;
	float dt	= t - m_beforeTime;
	m_beforeTime = t;

	FrameUpdatedEvent frame(dt, t);
	g_TaskService->BroadCast(&frame);

//	g_Console->UpdateConsole(evt);
	g_Log->ConsoleUpdate(&frame);

	return true;
}

void GameAppListener::debugState()
{
	if (g_Session == NULL)
		return;

	static String currFps = "Current FPS: ";
	static String avgFps = "Average FPS: ";
	static String bestFps = "Best FPS: ";
	static String worstFps = "Worst FPS: ";
	static String tris = "Triangle Count: ";
	static String time = "Session Time: ";

	// update stats when necessary
	try {
		OverlayElement* guiAvg = OverlayManager::getSingleton().getOverlayElement("Core/AverageFps");
		OverlayElement* guiCurr = OverlayManager::getSingleton().getOverlayElement("Core/CurrFps");
		OverlayElement* guiBest = OverlayManager::getSingleton().getOverlayElement("Core/BestFps");
		OverlayElement* guiWorst = OverlayManager::getSingleton().getOverlayElement("Core/WorstFps");

		const RenderTarget::FrameStats& stats = m_Window->getStatistics();
		guiAvg->setCaption(avgFps + StringConverter::toString(stats.avgFPS));
		guiCurr->setCaption(currFps + StringConverter::toString(stats.lastFPS));
		guiBest->setCaption(bestFps + StringConverter::toString(stats.bestFPS)
			+" "+StringConverter::toString(stats.bestFrameTime)+" ms");
		guiWorst->setCaption(worstFps + StringConverter::toString(stats.worstFPS)
			+" "+StringConverter::toString(stats.worstFrameTime)+" ms");

		OverlayElement* guiTris = OverlayManager::getSingleton().getOverlayElement("Core/NumTris");
		guiTris->setCaption(tris + StringConverter::toString(stats.triangleCount));

		OverlayElement* guiBatches = OverlayManager::getSingleton().getOverlayElement("Core/NumBatches");
		guiBatches->setCaption(time + StringConverter::toString(g_Session->GetSessionTime()));

		OverlayElement* guiDbg = OverlayManager::getSingleton().getOverlayElement("Core/DebugText");
		guiDbg->setCaption(m_DebugText);
	}
	catch(...) { /* ignore */ }
}

void GameAppListener::switchDebugOverlay()
{
	if (!m_DebugOverlay)
		return;

	m_EnabledDebugState = !m_EnabledDebugState;

	if (m_EnabledDebugState)
		m_DebugOverlay->show();
	else
		m_DebugOverlay->hide();
}

void GameAppListener::MoveCamera()
{
	g_Session->GetCamera()->yaw(m_camRotX);
	g_Session->GetCamera()->pitch(m_camRotY);
	g_Session->GetCamera()->moveRelative(m_TranslateVector);
}

void GameAppListener::UpdateInputVariable()
{
	if (m_MoveLeft)
		m_TranslateVector.x = -m_MoveScale;

	if (m_MoveRight)
		m_TranslateVector.x = m_MoveScale;

	if (m_MoveFwd)
		m_TranslateVector.z = -m_MoveScale;

	if (m_MoveBck)
		m_TranslateVector.z = m_MoveScale;

	m_MoveLeft = m_MoveRight = m_MoveFwd = m_MoveBck = false;

	if (m_RotateCam)
	{
		m_camRotX = Degree(-m_RotateAxisX * 0.13);
		m_camRotY = Degree(-m_RotateAxisY * 0.13);
		m_RotateCam = false;
	}
}

bool GameAppListener::keyPressed(const OIS::KeyEvent &arg)
{
	return true;
}
//////////////////////////////////////////////////////////////////////////

void GameAppInputHandler::OnEvent( Event* evt )
{
	BEGIN_EVENT_HANDLER(evt);
	
	ON_EVENT(InputKeyEvent)
	{
		if (evt->IsTriggered(OIS::KC_ESCAPE))
			appListener->ExitApp();

		if (evt->IsTriggered(OIS::KC_F10))
			appListener->switchDebugOverlay();

		if (evt->IsTriggered(OIS::KC_F7))
			g_App->Restart();
		
		if (evt->IsTriggered(OIS::KC_F9))
			g_Log->SetConsoleVisible(!g_Log->IsConsoleVisible());

		//g_Console->setVisible(!g_Console->isVisible());
		
	//	if (evt->IsTriggered(OIS::KC_F1))
	//		g_UIService->Load();

	//	if (evt->IsTriggered(OIS::KC_F2))
	//		g_UIService->ChangeVisible();

/*		if (!g_Console->isVisible())
		{
			if (evt->IsPressed(OIS::KC_W))
			{
				appListener->m_UpdateMovement = true;
				appListener->m_MoveFwd = true;
				appListener->m_IsKeyboardInput = true;
			}

			if (evt->IsPressed(OIS::KC_S))
			{
				appListener->m_UpdateMovement = true;
				appListener->m_MoveBck = true;
				appListener->m_IsKeyboardInput = true;
			}

			if (evt->IsPressed(OIS::KC_A))
			{
				appListener->m_UpdateMovement = true;
				appListener->m_MoveLeft = true;
				appListener->m_IsKeyboardInput = true;
			}

			if (evt->IsPressed(OIS::KC_D))
			{
				appListener->m_UpdateMovement = true;
				appListener->m_MoveRight = true;
				appListener->m_IsKeyboardInput = true;
			}
		}*/

	//	g_Console->UpdateKey(evt);
	}

	ON_EVENT(InputMouseEvent)
	{
	/*	if (evt->IsPressed(OIS::MB_Left))
		{
			appListener->m_RotateAxisX = evt->AX.rel;
			appListener->m_RotateAxisY = evt->AY.rel;
			appListener->m_RotateCam = true;
			appListener->m_UpdateMovement = true;
			appListener->m_IsMouseInput = true;
		}*/
	}

	END_EVENT_HANDLER;
}

